#include <e.h>
#include "e_mod_main.h"



static E_Config_DD *_core_config_entry=NULL;
static E_Config_DD *_widget_config_entry=NULL;


static Core *core;

#define BUFFER_SIZE 1024
static char *bufferstring;
/*
 ****************************************************************************************************** 
 *		Widget specs 
 * 
 ****************************************************************************************************** 
 */
 
 static Widget *_widget_new(E_Module *m,E_Gadcon * gc, const char *name, const char *id, const char *style)
{
	E_Gadcon_Client *gcc;
	Widget *w;
	Core *c;
	if (!(m))
		return;
	if (!(m->data))
		return;
	c=m->data;
	Evas_Object *o, *of, *ob;
	int i=0;
	w = E_NEW (Widget, 1);
	w->m=m;
	w->conf=_core_widget_config_get(c,id);
	if (!_widget_theme_init(w,gc->evas))
	{
		e_module_dialog_show(w->m,D_(MODULE_NAME"Desktop Widget"), D_("Theme init failed!"));
		_widget_free(w);
		return NULL;
	};
        
	gcc = e_gadcon_client_new (gc, name, id, style, w->canvas);
	gcc->data = w;
	w->gcc = gcc;
	evas_object_event_callback_add (w->canvas, EVAS_CALLBACK_MOUSE_DOWN,
				  _widget_cb_mouse_down, w);	
	return w;
}

static void _widget_free(Widget *w)
{
	if (likely(w))
	{
		if (w->config_dialog != NULL)
    		e_object_del (E_OBJECT (w->config_dialog));		
  		evas_object_event_callback_del (w->canvas, EVAS_CALLBACK_MOUSE_DOWN,_widget_cb_mouse_down);
		_widget_theme_shutdown(w);
		E_FREE(w);
	}	
}

/** 
 * @brief 
 * 
 * @param w 
 * @param evas 
 * 
 * @return 
 */
static int	_widget_theme_init(Widget *w, Evas *evas)
{
	char buf[PATH_MAX];
	char *format;
	if (!w->canvas)
	{
		if (evas)
		{
			w->canvas = edje_object_add (evas);
		}
		else
		{
			return 0;
		}
	}
	else
	{
		evas_object_hide(w->canvas);
	}
	snprintf (buf, sizeof (buf), "%s/themes/%s",e_module_dir_get (w->m),w->conf->theme);

	if (!edje_object_file_set (w->canvas, buf, "modules/"MODULE_NAME"/main"))
    {
    	snprintf (buf, sizeof (buf), "%s/themes/%s",e_module_dir_get (w->m),DEFAULT_THEME);
    	if (!edje_object_file_set (w->canvas, buf, "modules/"MODULE_NAME"/main"))
    		return 0;
    	e_module_dialog_show(w->m,D_(MODULE_NAME" Desktop Widget"), D_(MODULE_NAME "Theme init <hilight> failed!</hilight><br> Loaded" MODULE_NAME "default Theme."));	
    }
	if(!(format=edje_file_data_get(buf,"format")))
	{
		if (w->conf->format)
		{	
			w->conf->format=evas_stringshare_add(core->conf->format);
		}	
		else
		{
			w->conf->format=evas_stringshare_add(core->conf->format);
		}
	}
	else
	{
		if (w->conf->format)
		{	
			w->conf->format=evas_stringshare_add(format);
		}	
		else
		{
			w->conf->format=evas_stringshare_add(format);
		}
	}
	E_FREE(format);

/*
 * UnPremul ARG 		(Color << 8)/Alpha
 * Premul ARG			(Color*Alpha) >> 8
 * Each time color should be passed in premul 
 * if we want to detect rgb we should call evas_object_color_get and manualy unpremul them
 */  	
  	int tmp;
  	tmp=((255*w->conf->alpha) >> 8);
  	evas_object_color_set(w->canvas,tmp,tmp,tmp, w->conf->alpha);
  	evas_object_show(w->canvas);
  	return 1;	
}

static void _widget_theme_shutdown(Widget *w)
{
	if (w->canvas)
	{
		evas_object_del(w->canvas);
		w->canvas=NULL;	
	}
}

static void _widget_cb_mouse_down (void *data, Evas * e, Evas_Object * obj, void *event_info)
{
  Widget *w;
  Evas_Event_Mouse_Down *ev;
  w = data;
  ev = event_info;
  if (ev->button == 3)
    {
      E_Menu *mn;
      E_Menu_Item *mi;
      int x, y, width, height;

      mn = e_menu_new ();
      e_menu_post_deactivate_callback_set (mn, _widget_menu_cb_post, w);
      w->menu = mn;

      mi = e_menu_item_new (mn);
      e_menu_item_label_set (mi, D_("Configuration"));
      e_util_menu_item_edje_icon_set (mi, "enlightenment/configuration");
      e_menu_item_callback_set (mi, _widget_menu_cb_configure, w);

      mi = e_menu_item_new (mn);
      e_menu_item_separator_set (mi, 1);

      e_gadcon_client_util_menu_items_append (w->gcc, mn, 0);
      e_gadcon_canvas_zone_geometry_get (w->gcc->gadcon, &x, &y, &width, &height);
      e_menu_activate_mouse (mn,
			     e_util_zone_current_get (e_manager_current_get
						      ()), x + ev->output.x,
			     y + ev->output.y, 1, 1,
			     E_MENU_POP_DIRECTION_DOWN, ev->timestamp);
      evas_event_feed_mouse_up (w->gcc->gadcon->evas, ev->button,
				EVAS_BUTTON_NONE, ev->timestamp, NULL);
    }
}

static void _widget_menu_cb_configure (void *data, E_Menu * m, E_Menu_Item * mi)
{
	Widget *w;
	w = data;
	if (unlikely(!w))
		return;
	if (w->config_dialog!=NULL)  
		return;	
	w->config_dialog=_widget_config(w);
}

static void _widget_menu_cb_post (void *data, E_Menu * m)
{
	Widget *w;		
	w = data;
}

void _clock_widget_config_updated(Widget *w)
{
	if (unlikely(!w))
		return;	
	_widget_theme_init(w,NULL);
}


/*
 ****************************************************************************************************** 
 * Core Specs
 * 
 ****************************************************************************************************** 
 */


static Core *_core_new(void)
{
	Core *c;
	bufferstring=calloc(1,BUFFER_SIZE*sizeof(char));
	c = E_NEW(Core, 1);
	c->xss = NULL;
	c->dlck = NULL;
   	if (unlikely(!c))
	{
		printf("Malloc failure\n");
   	  return NULL;
	} 
   	if (!_core_config_load(c))
   	{
   		return NULL;
   	}
 	if (ecore_x_screensaver_event_available_get())
 	{
 		c->xss =  ecore_event_handler_add(ECORE_X_EVENT_SCREENSAVER_NOTIFY, _core_x_cb_screensaver_notify, c);
 		if (!c->xss)
 		{
 			printf("unable to set X Screen Saver Notify Handler\n");
 		}	
 	}
 	c->dlck = ecore_event_handler_add(E_EVENT_DESKLOCK, _core_e_cb_desklock_notify, c);
 	if (!c->dlck)
 	{
 		printf("unable to set E Desklock Event notifier\n");
 	}
 	
   	e_gadcon_provider_register(&_gc_class);
  	return c;
   	
}

static void _core_free(Core *c)
{
	if (unlikely(!c))
		return;
	if (c->config_dialog != NULL)
    	e_object_del (E_OBJECT (c->config_dialog));
	if (c->timer!=NULL)
		ecore_timer_del (c->timer);
	if (c->xss)
	{
		ecore_event_handler_del(c->xss);
	}
	if (c->dlck)
	{
		ecore_event_handler_del(c->dlck);
	}
	if (c->conf->theme)
		evas_stringshare_del(c->conf->theme);	
	while (c->conf->items)
    {
		Widget_Config *wc;
		wc = c->conf->items->data;
		c->conf->items = evas_list_remove_list (c->conf->items, c->conf->items);
		if (wc->id != NULL)
			evas_stringshare_del(wc->id);
		if (wc->theme!=NULL)
			evas_stringshare_del(wc->theme);
		if (wc->format!=NULL)
			evas_stringshare_del(wc->format);
      	E_FREE (wc);
    }
	e_gadcon_provider_unregister (&_gc_class);
	E_FREE(c->conf);
	E_FREE(bufferstring);
	E_FREE(c);
	E_CONFIG_DD_FREE (_widget_config_entry);
	E_CONFIG_DD_FREE (_core_config_entry);
}

static int _core_config_save(Core *c)
{
	if (unlikely(!c))
		return;
  	Evas_List *l;
	Widget *w;
    Widget_Config *wc;
	for (l = c->widgets; l; l = l->next)
    {
		w = l->data;
		wc = _core_widget_config_get(c,w->gcc->id);
		if (wc->id)
			evas_stringshare_del (wc->id);
		wc->id = evas_stringshare_add(w->gcc->id);
	}
	e_config_domain_save (MODULE_NAME, _core_config_entry, c->conf);
	return 1;
}

static int _core_config_load(Core *c)
{
	if (unlikely(!c))
		return;
		
	_widget_config_entry = E_CONFIG_DD_NEW (MODULE_NAME".widget", Widget_Config);
#undef T
#undef D
#define T Widget_Config
#define D _widget_config_entry
	E_CONFIG_VAL (D, T, id, STR);
	E_CONFIG_VAL (D, T, theme, STR);
	E_CONFIG_VAL (D, T, alpha, INT);
	E_CONFIG_VAL (D, T, format, STR);
#undef T
#undef D
	_core_config_entry = E_CONFIG_DD_NEW (MODULE_NAME".core",Core_Config);
#define T Core_Config
#define D _core_config_entry
	E_CONFIG_VAL (D, T, version, INT);
	E_CONFIG_VAL (D, T, theme, STR);
	E_CONFIG_VAL (D, T, alpha, INT);
	E_CONFIG_VAL (D, T, format, STR);
	E_CONFIG_VAL (D, T, poll_time, INT);
	E_CONFIG_LIST (D, T, items, _widget_config_entry);
	c->conf = e_config_domain_load (MODULE_NAME, _core_config_entry);
	if (c->conf == NULL)
    {
		c->conf = E_NEW (Core_Config, 1);
		c->conf->version = CONFIG_VERSION;
		c->conf->poll_time=1.0;
		c->conf->theme=evas_stringshare_add(DEFAULT_THEME);
		c->conf->format=evas_stringshare_add(DEFAULT_FORMAT);
		c->conf->alpha=255;
    }
	return 1;
}
static int _core_timer_set(Core *c, int on)
{
	if (!c)
		return 0;
	if (on == TIMER_OFF)
	{
		if (c->timer != NULL)
		{
			ecore_timer_del(c->timer);
			c->timer = NULL;
		}
	}
	else
	{
		if (c->timer == NULL)
		{
			c->timer=ecore_timer_add (c->conf->poll_time, _core_cb_update, c);
			_core_cb_update(c);
		}
	}
	return 1;	
}
static int _core_cb_update(void *data)
{
	Core *c;
 	Widget *w;
	Evas_List *l;
	time_t current_time;
	struct tm *local_time;
	c=data;
 	if (unlikely(!(c)))
 	{
 		return;
 	}

	if (c->widgets)
	{
		
		(void) time (&current_time);
		local_time = localtime (&current_time);
		for (l = core->widgets; l; l = l->next)
	    	{
		  		w = l->data;
		  		if (w)
		  			{
	    				strftime(bufferstring, BUFFER_SIZE, w->conf->format, local_time);
		 				edje_object_part_text_set (w->canvas, MODULE_NAME".text", bufferstring);
		  			}
		  		else continue;		
	    	}
	}
	/*
	 * returned 1 then continue calling timer 
	 * return 0 abort 
	 */
	return 1;	
}

 static int
_core_x_cb_screensaver_notify(void *data, int ev_type __UNUSED__, void *ev)
{
	Core *c;
	Ecore_X_Event_Screensaver_Notify *e;
	e = ev;
	c = data;
	if (!c)
		return 1;
	if (!e)
		return 1;
	_core_timer_set(c, e->on);
	return 1;
}
 static int
_core_e_cb_desklock_notify(void *data, int ev_type __UNUSED__, void *ev)
{
	Core *c;
	E_Event_Desklock *e;
	e = ev;
	c = data;
	if (!c)
		return 1;
	if (!e)
		return 1;
	_core_timer_set(c, e->on);
	return 1;
}

static Widget *_core_widget_add(Core *c,E_Gadcon * gc, const char *name, const char *id, const char *style)
{
	Widget *w;
	if (unlikely(!c))
		return NULL;
	_core_timer_set(c, TIMER_OFF);
	w=_widget_new(c->m,gc,name,id,style);
	if (unlikely(!w))
		return NULL;
	c->widgets =evas_list_append(c->widgets, w);
	_core_timer_set(c, TIMER_ON);
  	return w;
}

static Widget_Config *_core_widget_config_get(Core *c, const char *id)
{
	Evas_List *l;
	Widget_Config *wc;
	if (unlikely(!c))
		return NULL;
	for (l = c->conf->items; l; l = l->next)
	{
		wc = l->data;
		if (wc->id == NULL)
			continue;
		if (strcmp (wc->id, id) == 0)
			return wc;
    }
    wc = E_NEW (Widget_Config, 1);
    wc->id = evas_stringshare_add (id);
    wc->theme = evas_stringshare_add(c->conf->theme);
    wc->alpha = c->conf->alpha;
    wc->format = evas_stringshare_add(c->conf->format);
    c->conf->items = evas_list_append (c->conf->items, wc);
  return wc;	
}
static void _core_widget_delete(Core *c, Widget *w)
{
	if (unlikely(!c))
		return;
	_core_timer_set(c, TIMER_OFF);
	if (unlikely(!w))
		return;
	c->widgets = evas_list_remove(c->widgets, w);
	if (c->widgets)
	{
		_core_timer_set(c, TIMER_ON);
	}	
	_widget_free(w);
}

void _clock_core_config_updated(Core *c)
{
	if (unlikely(!c))
		return;
}

/*
 ****************************************************************************************************** 
 *		Gadcon specs 
 * 
 ****************************************************************************************************** 
 */
 
 static E_Gadcon_Client *_gc_init (E_Gadcon * gc, const char *name,const char *id, const char *style)
{
	Widget *w;
	w = _core_widget_add(core,gc,name,id,style);
	if (unlikely(!w))
		return NULL;
	else
		return w->gcc;
}


static void _gc_shutdown (E_Gadcon_Client * gcc)
{
	E_Module *m;
	Core *c;
	Widget *w;
	if (unlikely(!gcc))
		return;
	w = gcc->data;
	if (unlikely(!w))
		return;
	m=w->m;
	if (unlikely(!m))	
		return;
	c=m->data;
	if (unlikely(!c))
		return;
	_core_widget_delete(c,w);
  
}
static void _gc_orient (E_Gadcon_Client * gcc)
{
	Widget *w;
	Evas_Coord width, height;
	w = gcc->data;
	if (unlikely(!w))
		return;
	switch (gcc->gadcon->orient)
	{
		case E_GADCON_ORIENT_FLOAT:
		case E_GADCON_ORIENT_HORIZ:
		case E_GADCON_ORIENT_VERT:
		case E_GADCON_ORIENT_LEFT:
		case E_GADCON_ORIENT_RIGHT:
		case E_GADCON_ORIENT_TOP:
		case E_GADCON_ORIENT_BOTTOM:
		case E_GADCON_ORIENT_CORNER_TL:
		case E_GADCON_ORIENT_CORNER_TR:
		case E_GADCON_ORIENT_CORNER_BL:
		case E_GADCON_ORIENT_CORNER_BR:
		case E_GADCON_ORIENT_CORNER_LT:
		case E_GADCON_ORIENT_CORNER_RT:
		case E_GADCON_ORIENT_CORNER_LB:
		case E_GADCON_ORIENT_CORNER_RB:
			width = 16;
			height = 16;
		default:
		break;
	}
	
	edje_object_size_min_calc (w->canvas, &width, &height);
	e_gadcon_client_min_size_set (gcc, width, height);
}
static char *_gc_label (void)
{
	return MODULE_NAME;
}
static Evas_Object *_gc_icon (Evas * evas)
{
	Evas_Object *o;
	char buf[4096];
	o = edje_object_add (evas);
	snprintf (buf, sizeof (buf), "%s/data/module.edj",e_module_dir_get(core->m));
	edje_object_file_set (o, buf, "icon");
	return o;
}
static const char *_gc_id_new(void)
{
   return _gc_class.name;
}
/*
 ****************************************************************************************************** 
 * E_MODULE_API Staff 
 * dl directly look into module.so and fill references
 ****************************************************************************************************** 
 */
 
EAPI E_Module_Api e_modapi = 
   {
      E_MODULE_API_VERSION,
      MODULE_NAME
   };
   
EAPI void *e_modapi_init (E_Module *m)
{
//  Core *c;
// 
  if (unlikely(!m))
	 return NULL;
  bindtextdomain(PACKAGE, LOCALEDIR);
  bind_textdomain_codeset (PACKAGE, "UTF-8");
  core = _core_new();
  if (unlikely(!core)) 
	return NULL;	
  core->m = m;
  m->data = core;
  return core;
}

/*EAPI int
e_modapi_config(E_Module *m)
{
   Core *c;
   if (unlikely(!m)) return 0;
   if (unlikely(!(m->data))) return 0;
   c=m->data;
   if (c->config_dialog)
   		return 0;
   c->config_dialog=_core_config(c);
   return 1;
}
*/


EAPI int e_modapi_shutdown (E_Module *m)
{
	Core *c;
	c = m->data;
	if (likely(c))
	   _core_free(c);
  return 1;
}

EAPI int e_modapi_save (E_Module *m)
{
  Core *c;
  c = m->data;
  if(likely(c))
  	{
  		_core_config_save(c);
  	}
  return 1;
}

/*
EAPI int e_modapi_about (E_Module *m)
{
  e_module_dialog_show (m, D_ ("Enlightenment Clock Module"),
			D_ ("This module is used to show System Time."));
  return 1;
}
*/
